<!--
 * @Author: your name
 * @Date: 2021-06-26 13:21:35
 * @LastEditTime: 2023-11-02 11:48:54
 * @LastEditors: pmy
 * @Description: 实时定位树
 * @FilePath: \bdcar-net\src\views\trajectoryMonitor\realtimePosition\realtimeTree.vue
-->
<script lang="ts">
import { ref } from 'vue';
import { useData } from "../../../api/tree"
export default {
  props: {
    defaultCheckedNode: {
      type: Array,
      default: ['0'],
    },
    handleCheckChange: {
      type: Function,
      default: () => { }
    },
    nodeClick: {
      type: Function,
      default: () => { }
    },
    rightMenuClick: {
      type: Function,
      default: () => { }
    },
    videoClick: {
      type: Function,
      default: () => { }
    },
    dataRefresh: {
      type: Function,
      default: () => { }
    },
    treeList: Array,
  },
  name: "realtimeTree",
  setup() {
    const {
      showTree,
      filterText,
      debounce,
    } = useData();
    const realtimeTree = ref();
    const selectData: any = ref({});
    return {
      showTree,
      filterText,
      currentNode: null,
      realtimeTree,
      selectData,
      debounce
    };
  },
  created() {
  },
  mounted() {
  },
  methods: {
    myRequire(str) {
      return new URL(`../../../assets/img/${str}`, import.meta.url).href
    },
    getIsOnline(obj: { vehicleStatus: string }) {
      let _string = obj.vehicleStatus
      //@ts-ignore
      return GlobalSetting.onlineStatus.some(v => { return v == _string })
    },
    nodeClickHandle(data: any) {
      // 转换一下防止参数覆盖
      if (data.type === 2) {
        this.nodeClick(data)
        this.currentNode = data.id
      }
    },
    //过滤树节点
    filterMethod(query: string, node: any) {
      if (!query) return true;
      function compareOneEqualTwo(initStr: string, searchStr: string) {
        let reg = new RegExp(searchStr, "i");
        return initStr.toString().match(reg) != null;
      }
      return compareOneEqualTwo(this.getText(node), query) || (node.deviceNo && compareOneEqualTwo(node.deviceNo, query));
    },
    getText(data) {
      let str = data.label ?? data.shortName ?? data.deptName ?? data.numberPlate
      return str
    },
    getCheckedNodes() {
      return this.realtimeTree.getCheckedNodes();
    },
    setCheckedKeys(carId: string) {
      let _this = this;
      _this.realtimeTree.setCheckedKeys([carId]);
    },
    getNodeImg(data: any) {
      let imgHash: any = {
        0: "company",
        1: "department",
      }
      if (imgHash[data.type]) {
        return imgHash[data.type]
      }
    },
    contextmenuHandle(e: any, data, node) {
      // type -1：根节点   0:公司    1:部门   2：车
      this.selectData = data;
      const menu = this.$refs.treeMenu;
      const menuDom = this.$refs.menuDom;
      menuDom.classList.add('active');

      this.$nextTick(() => {
        const menuHeight = menu.clientHeight
        const menuWidth = menu.clientWidth
        const x = e.pageX // 触发节点到页面窗口左边的距离
        const y = e.pageY  // 触发节点到页面窗口顶部的距离

        // 如果会超出屏幕右边则停靠屏幕右边  因为左右侧给了40像素的边距，所以计算的时候需要减去
        const rightNum = window.innerWidth - x;
        if (rightNum >= menuWidth) {
          menuDom.style.right = rightNum - menuWidth - 40 + 'px'
        } else {
          menuDom.style.right = '-40px'
        }

        // 如果会超出屏幕下边则停靠屏幕下边
        const rightTreeDomHeight = document.getElementById('realtimeCarTree').clientHeight;
        const topFixHeight = document.getElementsByClassName('top-block')[0].clientHeight;
        const bottomNum = rightTreeDomHeight - (y - topFixHeight);
        if (bottomNum >= menuHeight) {
          menuDom.style.top = y - topFixHeight + 'px'
        } else {
          menuDom.style.top = rightTreeDomHeight - menuHeight + 'px';
        }
      })
    },
    rightMenuHandle(param) {
      this.closeMenu();
      this.rightMenuClick(param, this.selectData);
    },
    closeMenu() {
      const menuDom = this.$refs.menuDom
      menuDom.classList.remove('active');
    },
  },
  watch: {
    filterText(val) {
      let _this = this;
      function myFun() {
        // 此处val是string
        if (val === '') {
          _this.showTree = false
          _this.$nextTick(() => {
            _this.showTree = true
          })
        } else {
          _this.realtimeTree.filter(val);
        }
      }
      _this.debounce(myFun);
    },
    treeList(val) {
      if (this.filterText !== '') {
        this.$nextTick(() => {
          this.realtimeTree.filter(this.filterText);
        })
      }
    }
  },
};
</script>
<template>
  <div class="realtimeTree">
    <div class="search-dom">
      <el-input placeholder="请输入关键字" v-model="filterText" clearable>
      </el-input>
      <el-icon class="refresh-btn" @click="dataRefresh(true)">
        <RefreshRight />
      </el-icon>
      <el-tooltip effect="dark" content="右键树的节点可对公司或者设备进行操作,鼠标离开右键<br>菜单较远时,右键菜单会自动关闭。" placement="top-start"
        :raw-content="true">
        <el-icon>
          <QuestionFilled />
        </el-icon>
      </el-tooltip>
    </div>
    <div class="body" id="treeBody">
      <el-auto-resizer>
        <template #default="{ height, width }">
          <!-- 目前这里必须初始化之前存在expanded的数据才可以正常展开 -->
          <el-tree-v2 v-if="showTree" :data="treeList" :default-expanded-keys="['0']" class="my-tree"
            :default-checked-keys="defaultCheckedNode" :expand-on-click-node="false" @check-change="handleCheckChange"
            ref="realtimeTree" :show-checkbox="true" :highlight-current='true' :filter-method="filterMethod"
            :height="height" @node-contextmenu="contextmenuHandle">
            <template #default="{ data }">
              <div class="my-tree-node overflow-text" @click='nodeClickHandle(data)'>
                <!-- 叶子图标 -->
                <span v-if="data.type == 2"
                  :class="{ online: data.vehicleStatus != '离线', offline: data.vehicleStatus == '离线' }"></span>
                <div v-else-if="data.type < 2 && data.type >= 0" class="node-icon">
                  <svg-icon :icon-class="getNodeImg(data)" />
                </div>
                <!-- 叶子内容 -->
                <div class="node-text" :title="getText(data)">{{ getText(data) }}</div>
                <!-- 公司在线设备计数 -->
                <span v-if="data.type !== 2">
                  （<span style="color:rgb(5,185,47)">{{ data.onlineNum }} </span>/<span>{{ data.total }}</span>）
                </span>
                <!-- 设备视频 -->
                <img src="@/assets/img/tree/treeVideo-1.png"
                  v-if="data.type === 2 && data.channelsNum && getIsOnline(data)" class="tree-video"
                  @click.stop="videoClick(data)" />
                <img src="@/assets/img/tree/treeVideo.png" style="cursor:not-allowed"
                  v-if="data.type === 2 && data.channelsNum && !getIsOnline(data)" class="tree-video"
                  @click.stop="() => { }" />
                <!-- remark设备状态 -->
                <span v-if="data.type == 2" class="node-remark overflow-text" :title="data.remark">{{ data.remark
                }}</span>
              </div>
            </template>
          </el-tree-v2>
          <!-- 右键弹出框，嵌套一层增加触发范围 -->
          <div ref="menuDom" class="tree-menu" @mouseleave="closeMenu">
            <!-- type -1：根节点   0:公司    1:部门   2：车 -->
            <ul ref="treeMenu">
              <li @click="rightMenuHandle('createChild')"
                v-if="selectData.type == '-1' || selectData.type == '0' || selectData.type == '1'">创建子节点</li>
              <li @click="rightMenuHandle('rename')" v-if="selectData.type == '0' || selectData.type == '1'">重命名</li>
              <li @click="rightMenuHandle('addEquip')" v-if="selectData.type == '0' || selectData.type == '1'"
                v-hasPermi="['trajectoryMonitor:realtimePosition:addEquip']">新增设备</li>
              <li @click="rightMenuHandle('changeCompany')" v-if="selectData.type == '0' || selectData.type == '1'"
                v-hasPermi="['trajectoryMonitor:realtimePosition:changeNode']">迁移节点</li>
              <li @click="rightMenuHandle('deleteCompany')" v-if="selectData.type == '0' || selectData.type == '1'"
                v-hasPermi="['trajectoryMonitor:realtimePosition:removeNode']">删除节点</li>
              <li @click="rightMenuHandle('bindRules')" v-if="selectData.type == '2'">已绑规则</li>
              <li @click="rightMenuHandle('changeEquip')" v-if="selectData.type == '2'"
                v-hasPermi="['trajectoryMonitor:realtimePosition:changeEquip']">迁移设备</li>
              <li @click="rightMenuHandle('deleteEquip')" v-if="selectData.type == '2'"
                v-hasPermi="['trajectoryMonitor:realtimePosition:removeEquip']">删除设备</li>
            </ul>
          </div>
        </template>
      </el-auto-resizer>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.tree-menu {
  position: fixed;
  visibility: hidden;
  color: #223355;
  font-size: 14px;
  padding: 0 40px;

  ul {
    width: 100px;
    border: 1px solid #DEDEDF;
    border-radius: 6px;
    background-color: #ffffff;
    box-shadow: 0 6px 24px #F4F5F5;
    padding: 8px 2px;
    box-sizing: border-box;
  }

  li {
    text-align: center;
    line-height: 32px;
    cursor: pointer;

    &:hover {
      background-color: #D6EDFF;
      color: #3388FF;
    }
  }

  &.active {
    visibility: visible;
    z-index: 2;
  }
}

.realtimeTree {
  padding: 16px;
  height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;

  .search-dom {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-items: left;
    margin-bottom: 10px;
    flex-direction: row;
    color: var(--el-color-primary);
  }

  .body {
    width: 100%;
    flex: 1;
    overflow: auto;
    position: relative;
  }

  .my-tree {
    font-size: 14px;
    height: 100%;

    .my-tree-node {
      display: flex;
      flex: 1;
      align-items: center;
      color: #666;

      .online {
        width: 6px;
        height: 6px;
        background: #11C79B;
        border-radius: 50%;
        margin-right: 3px;
        min-width: 6px;
      }

      .offline {
        width: 6px;
        height: 6px;
        background: #CDD3CF;
        border-radius: 50%;
        margin-right: 3px;
        min-width: 6px;
      }

      :deep(.tree-dropdown) {
        margin-left: auto;
        margin-right: 15px;
      }

      .tree-video {
        width: 20px;
        height: 20px;
        margin: 0 10px;
        cursor: pointer;
      }

      .node-text {
        width: fit-content;
      }

      .node-remark {
        margin-left: 8px;
        color: #C3CAD9;
        width: 80px;
      }
    }
  }
}
</style>
